<?php
/**
 * $Id: JXwebAPI.php 1 2009-07-30 10:06:11Z hainam $
**/

define('JXW_ACTION_XAY', 1);
define('JXW_ACTION_HERO_ASK', 6);
define('JXW_ACTION_HERO_LEAVE', 8);
define('JXW_ACTION_HERO_QUICKASK', 27);
define('JXW_ACTION_HUANLUYEN', 9);
define('JXW_ACTION_CHIEUMO', 10);
define('JXW_ACTION_LUYENNHANH', 17);
define('JXW_ACTION_TUYENNHANH', 18);
define('JXW_ACTION_BEQUAN', 23);
define('JXW_ACTION_HOIPHUC', 7);
define('JXW_ACTION_CONGKICH', 11);
define('JXW_ACTION_TROVE', 13);
define('JXW_ACTION_THUTHAP', 14);
define('JXW_ACTION_LUYENNHANH', 17);
define('JXW_ACTION_TUYENNHANH', 18);
define('JXW_ACTION_TRIEUHOINHANH', 19);
define('JXW_ACTION_DOTHAM', 25);
define('JXW_ACTION_THUTHAPNHIEMVU', 15);
define('JXW_ACTION_TIMTHOREN', 24);
define('JXW_OBJ_HERO', 1);
define('JXW_OBJ_DEFENCE', 3);
define('JXW_MAP_BUILDING', 1);
define('JXW_MAP_DEFENCE', 2);
define('JXW_MAP_WORLD', 3);
define('JXW_UNIT_CITY', 5);
define('JXW_UNIT_NPC', 6);
define('JXW_UNIT_NPC_OPEN', 7);
define('JXW_TECHNIC_DSDH', 1);
define('JXW_TECHNIC_TMKK', 2);
define('JXW_TECHNIC_CHNS', 3);
define('JXW_TECHNIC_KTTT', 4);
define('JXW_TECHNIC_TCTuT', 5);
define('JXW_TECHNIC_TCTiT', 6);
define('JXW_TECHNIC_TCCB', 7);
define('JXW_TECHNIC_TCCM', 8);
define('JXW_TECHNIC_TCLT', 9);
define('JXW_TECHNIC_LBMM', 10);
define('JXW_TECHNIC_ULT', 11);
define('JXW_TECHNIC_HLT', 12);
define('JXW_TECHNIC_DLKC', 13);
define('JXW_TECHNIC_UDCG', 14);
define('JXW_TECHNIC_LHCC', 15);
define('JXW_ITEM_STATE_BINHTHUONG', 1);
define('JXW_ITEM_STATE_VANCHUYEN', 2);
define('JXW_ITEM_STATE_TRANGBI', 3);
define('JXW_ITEM_STATE_DANGBAN', 4);
define('JXW_ITEM_STATE_NGOAI', 5);
define('JXW_ITEM_TYPE_RES', 3);
define('JXW_ITEM_TYPE_OPEN', 2);
define('JXW_HERO_STATE_DOILENH', 1);
define('JXW_HERO_STATE_TRONGTHUONG', 2);
define('JXW_HERO_STATE_CHIEUMO', 3);
define('JXW_HERO_STATE_HUANLUYEN', 4);
define('JXW_HERO_STATE_TAINGOAI', 5);
define('JXW_HERO_STATE_NGOAITHUONG', 6);
define('JXW_HERO_STATE_CHIVIEN', 7);
define('JXW_HERO_STATE_BEQUAN', 8);
define('JXW_HERO_LIST_HAUBI', 1);
define('JXW_HERO_LIST_TANCONG', 2);
define('JXW_HERO_LIST_BOPHONG', 3);
define('JXW_DEF_TUONG', 1);
define('JXW_DEF_HAO', 2);
define('JXW_DEF_BAY', 3);
define('JXW_DEF_MOC', 4);
define('JXW_DEF_THACH', 5);
define('JXW_DEF_THAP', 6);
define('JXW_ITEM_QUALITY_THANH', 3);
define('JXW_ITEM_QUALITY_LAM', 4);

chdir(dirname(__FILE__));// for CLI mode

$params = array(
  JXW_TECHNIC_LBMM => array(0,0,0,91,88,0,0,0,0,0,0,68,66,64,0,0,0,0,0,0,0),
  JXW_TECHNIC_ULT => array(14,16,19,22,25,28,30,33,36,39,42,45,50,55,60,65,70,75),//not sure from 5 to 11
  JXW_TECHNIC_LHCC => array(100,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81),
);

require_once 'JSON.php';
require_once 'HTTP.php';
require_once 'AjaxPro.php';
require_once 'Tools.php';
require_once 'JXAccounts.php';
require_once 'template.php';
require_once 'settings.php';

class JXwebAPI {
  var $user, $cookie, $config, $cfgFile, $temp;
  var $CityID, $CityPos;
  var $hooks = array(
                      'UpdateUserInfo' => array(),
                      'UpdateHeroInfo' => array(),
                     );
  var $needUpdate;
  
  public static $maxLogins = 2;
  public static $checkTime = 45;  // check at least every 5 minutes
  public static $loopTime = 86400;
  public static $attackTime = 3600; // khoang cach toi thieu giua 2 lan cuop

  function __construct($user = null) {
    $this->template = &$GLOBALS['TMPL'];

    if ($user) $this->loadUser($user);
  }

  function hook($hookname) {
    foreach ($this->hooks[$hookname] as $hook) {
      call_user_method($hook, $this);
    }
  }

  function loadUser($user) {
    $this->user =& $user;

    $server = $this->user['server'] .'.volamweb.zing.vn';
    $this->url = array(
      'auth' => 'https://app.zing.vn/auth/index.php/login/auth',
      'login' => 'http://idvolamweb.zing.vn/jxw/',
      'ajax' => 'http://'. $server .'/ajaxpro/'. JXW_CORE_AJAX,
      'server' => 'http://idvolamweb.zing.vn/jxw/may-chu/index.'. intval(substr($this->user['server'],1)) .'.html',
      'waiting' => 'http://'. $server .'/EnterWaiting_VN.aspx',
      'main' => 'http://'. $server .'/Main_vina.aspx?version=vina',
    );
    //$this->cfgFile = sprintf('data/config-%s-%s.txt', $user['username'], $user['server']);
    $this->cfgFile = sprintf('data/config/%s-%s.txt', $user['username'], $user['server']);
    $this->loadConfig();
  }

  function loadConfig() {
    if (file_exists($this->cfgFile)) {
      $this->config = unserialize(file_get_contents($this->cfgFile));
    }
    else {
      $this->config = array(
        'cookie' => '',
        'options' => array(),
        'needUpdate' => 0,
        'UserInfo' => null,
        'HeroInfo' => null,
      );
    }
    $this->cookie = &$this->config['cookie'];
  }

  function saveConfig() {
    file_put_contents($this->cfgFile, serialize($this->config));
  }

  function init() {
    if (! $this->updateOnline()) {
      die('Cannot log in to game.');
    }

    $this->updateUserInfo();
  }

  function alert($msg, $CityInfo = true) {
    if (isset($this->user['email'])) {
      if ($CityInfo) {
        $msg = "For {$this->config['UserInfo']['Name']} (city {$this->config['UserInfo']['CityName']}, server {$this->user['server']}):\n\n" . $msg;  
      }
      require_once('phpmailer/class.phpmailer.php');
      $mail = new PHPMailer();
      $mail->IsSMTP();
      $mail->Host = 'ssl://smtp.gmail.com';
      $mail->Port = 465;
      $mail->SMTPAuth = true;
      $mail->Username = JXW_CORE_EMAIL;
      $mail->Password = JXW_CORE_EMAIL_PWD;
      $mail->SetFrom(JXW_CORE_EMAIL, 'JXwebAuto');
      $mail->AddAddress($this->user['email']);
      $mail->Subject = 'Thong bao cua JXwebAuto';
      $mail->Body = $msg;
      $mail->Send();
      addLog('Send mail to '. $this->user['email']);
    }
  }

  function login() {
    $data = drupal_http_request($this->url['login']);

    $request_str = implode('&', array(
      'username='. $this->user['username'],
      'password='. $this->user['password'],
      'ActionField=ActionField',
      '_FormName_=_RegisterForm_',
      'group=LOGIN',
      'appid=JXW',
      'sign='.substr($data->data,strpos($data->data,'name="sign" id="sign"')+29,32),
      'time='.substr($data->data,strpos($data->data,'name="time" id="time"')+29,10),
      'submit2.x=0&submit2.y=0&submit2=%C4%90%C4%83ng+nh%E1%BA%ADp',
    ));

    if (isset($data->headers['Set-Cookie'])) {
      $this->cookie = $data->headers['Set-Cookie'];
    }

    $header = array(
      'Cookie' => $this->cookie,
      'Content-Type' => 'application/x-www-form-urlencoded',
    );

    $data = drupal_http_request($this->url['auth'], $header, 'POST', $request_str, 0);
    $data->data = substr($data->data, 0, 1000);
    addDebug($data);

    if ($data->code=='302'){
      unset($header['Content-Type']);
      $data = drupal_http_request($data->redirect_url, $header, 'GET', null, 0);
      addDebug($data);
    }

    $data = drupal_http_request($this->url['server'], $header, 'GET', null, 0);
    addDebug($data);

    if ($data->code=='302'){
      unset($header['Content-Type']);
      $data = drupal_http_request($data->redirect_url, $header, 'GET', null, 0);
      if (isset($data->headers['Set-Cookie'])) {
        $this->cookie = $data->headers['Set-Cookie'];
      }

      $header = array(
        'Cookie' => $this->cookie,
      );
      addDebug($data);
      if ($data->code=='302'){
        $data = drupal_http_request($this->url['waiting'], $header, 'GET', null, 0);
        addDebug($data);
        if ($data->code=='302'){
          unset($header['"Content-Type"']);
          $data = drupal_http_request($this->url['main'], $header, 'GET', null, 0);
          addDebug($data);
          // auto detect AjaxUrl
          //          if (preg_match('/Main,App_Web_[0-9a-z]+\.ashx/', $data->value, $matches)) {
          //            self::$app = $matches[0];
          //            $this->url['ajax'] = 'http://'. $server .'/ajaxpro/'. self::$app;
          //          }
        }
      }
    }
    return;
  }

  function updateOnline() {
    $result = ajax_UpdateUserOnline();
    $retry = 0;
    if (Tools::decode($result->data) === 0 ) {
      //addLog("Update online status sucessfully.");
    }
    else {
      while ($errorCode = Tools::decode($result->data) !== 0 && $retry < self::$maxLogins){
        addLog("Update online status failed, error code: $errorCode. Attempt to relogin: ". ++$retry);
        $this->login();
        $result = ajax_UpdateUserOnline();
        addDebug($result);
      }
    }
    return ($retry < self::$maxLogins);
  }

  function updateUserInfo($force = false) {
    if ($this->config['needUpdate'] > 0 && time()>$this->config['needUpdate']) {
      $force = true;
      $this->config['needUpdate'] = 0;
    }

    if (empty($this->config['UserInfo']) || $force) {
      $result = ajax_GetUserInfo();
      $tmp = Tools::decode($result->data);
      $this->config['UserInfo'] = array_merge(
        Tools::arrayExport($tmp, array('Organise', 'ID', 'Name')),
        Tools::arrayExport($tmp->CityList[0], array('Name' => 'CityName', 'Pos' => 'CityPos'))
      );
      $this->config['UserInfo']['CityID'] = $tmp->CityList[0]->ID;
    }

    $this->CityID = $this->config['UserInfo']['CityID'];
    $this->CityPos = $this->config['UserInfo']['CityPos'];
    if (empty($this->config['CityInfo']) || $force) {
      $result = ajax_GetCityInteriorInfo($this->CityID);
      $tmp = Tools::decode($result->data);
      $this->config['CityInfo'] = Tools::arrayExport($tmp, array('Men', 'Food', 'Money', 'Gold', 'MenRoom', 'FoodRoom', 'MoneyRoom', 'Child', 'Bloom', 'TechnicLevel'));
    }
    
    if (empty($this->config['Buildings']) || $force) {
      $result = ajax_GetMapUnitInfo($this->CityID, JXW_MAP_BUILDING, 0);
      $buildings = Tools::decode($result->data);
      
      $MP = array();
      foreach ($buildings as $b) {
        if ($b->Index >=12 && $b->Index <= 21) {// nha Mon phai
          $MP[] = Tools::arrayExport($b, array('Name', 'Level', 'ID', 'Pos', 'Index'));
        }
      }
      $this->config['Buildings'] = $MP;
    }

    if (empty($this->config['HeroInfo']) || $force) {
      $this->updateHeroInfo();
    }
    
    if (! is_array($this->config['Actions'])) { // actions done
      $this->config['Actions'] = array('event'=>array(), 'op'=>array());
    }
    
    $this->saveConfig();
  }

  function updateHeroInfo() {
    $result = ajax_GetCityHero($this->CityID);
    $tmp = Tools::decode($result->data);
    $this->config['HeroInfo'] = array();
    if (is_array($tmp)) {
      foreach ($tmp as $k=>$v) {
        //Junta (JS: UnionName)
        $this->config['HeroInfo'][$k] = Tools::arrayExport($v, array('Quality', 'Training', 'PrenticeNum', 'DefencePos', 'ID', 'Level', 'Name', 'Junta', 'ListType', 'Attack', 'Defence', 'CrushBlow', 'Dodge', 'MaxPrenticeNum', 'LevelExp', 'State', 'CorpsID', 'LevelExpStatic'));
        $this->config['HeroInfo'][$k]['ItemList'] = array();
        for ($j=0; $j<count($v->ItemList); $j++) {
          $this->config['HeroInfo'][$k]['ItemList'][$j] = Tools::arrayExport($v->ItemList[$j], array('Attack', 'Defence', 'CR', 'DR', 'FR', 'LR', 'ID'));
          if (
              $this->config['options']['repair'] &&
              $v->ItemList[$j]->Durability <= 1 &&
              !in_array($v->State, array(JXW_HERO_STATE_NGOAITHUONG, JXW_HERO_STATE_TAINGOAI))
          ) {
            if (
                $this->config['options']['repair_opt'] == 'bt' ||
                ($this->config['options']['repair_opt'] == 'tim' && $v->ItemList[$j]->Quality != JXW_ITEM_QUALITY_LAM)
            ) {
              $this->vatpham($v->ItemList[$j], 'sua');
            }
            else {
              $this->vatpham($v->ItemList[$j], 'suaki');
            }
          }
        }
        $this->config['HeroInfo'][$k]['SkillList'] = array();
        for ($j=0; $j<count($v->SkillList); $j++) {
          $this->config['HeroInfo'][$k]['SkillList'][$j] = Tools::arrayExport($v->SkillList[$j], array('EffValue', 'Level'));
        }
      }
    }
    
    $this->needUpdate['HeroInfo'] = false;
    $this->hook('UpdateHeroInfo');
  }

  function getNPCInfo($Pos) {// NPC or City
    static $NPCs = array();
    
    if (! isset($NPCs[$Pos])) {
      $result = ajax_GetMapUnitInfo($this->CityID, JXW_MAP_WORLD, $Pos);
      $MapUnitInfo = Tools::decode($result->data);
      if (is_array($MapUnitInfo)) {
        foreach ($MapUnitInfo as $Unit) {
          //$NPCs[$Unit->Pos] = Tools::arrayExport($Unit, array(
          //    'AttackCount', 'CityName', 'Quality', 'State', 'Type', 'UserName', 'IniteCount', 'LevelDifferenceFlag',
          //    'NpcFloor', 'NpcFloorMax', 'NpcFloorJunta', 'Name', 'Level', 'Pos', 'ID', 'JuntaName', 'JuntaState' //JuntaName: bang hoi (City)
          //));
          $NPCs[$Unit->Pos] = $Unit;
        }
      }
    }

    return empty($NPCs[$Pos]) ? false : $NPCs[$Pos];
  }
  
  function getLandsInfo($Pos) {
    $result = ajax_GetWorldLandform($this->CityID, $Pos);
    $LandformInfo = Tools::decode($result->data);
    $result = ajax_GetMapUnitInfo($this->CityID, JXW_MAP_WORLD, $Pos);
    $MapUnitInfo = Tools::decode($result->data);

    // Get list of Free spaces and NPC, we don't care about Cities
    // Cities will be searched later within a broader range
    $Lands = array('Spaces'=>array(), 'NPCs'=>array());

    if (is_array($LandformInfo) && is_array($MapUnitInfo)) {
      $Cities = array();
      foreach ($MapUnitInfo as $Unit) {
        $Cities[] = $Unit->Pos;
        if ($Unit->Type != JXW_UNIT_CITY) {
          $Lands['NPC'][] = Tools::arrayExport($Unit, array('NpcFloor', 'NpcFloorMax', 'NpcFloorJunta', 'Name', 'Level', 'Pos'));
        }
      }
      foreach ($LandformInfo as $Land) {
        if (! in_array($Land->Pos, $Cities)) {
          $Lands['Spaces'][] = $Land->Pos;
        }
      }
    }
    
    return $Lands;
  }

  function getJuntaBuilding($Junta) {
    $p = -1;
    for ($k=0; $k<count($this->config['Buildings']); $k++) {
      if ($this->config['Buildings'][$k]['Index'] == $Junta + 11) {
        $p = $k;
      }
    }
    return ($p >= 0) ? $this->config['Buildings'][$p] : false;
  }
  
  function calculatePower($Hero) {
    // ATT va DEF da cong don tu trang bi
    $ATT = $Hero['Attack'];
    $DEF = $Hero['Defence'];
    
    $RES = 0;
    foreach ($Hero['ItemList'] as $i) {
      if ($i['Durability'] > 0)
        $RES += $i['CR'] + $i['DR'] + $i['FR'] + $i['LR'];
    }
    
    $PRE = $Hero['PrenticeNum']*$Hero['Training'];
  }
  
  function vatpham($Item, $action, $option = 0) {
    $ret = false;
    switch ($action) {
   		case 'sudung':
        if ($Item->UseType == JXW_ITEM_TYPE_RES) {
          ajax_UseItemRes($this->CityID, $Item->ID);
  			}
  			elseif ($Item->UseType == JXW_ITEM_TYPE_OPEN) {
          ajax_UseItem($this->CityID, $Item->ID);
        }
  			break;
  		case 'huyban':
  			ajax_CancleSellItem($this->CityID, $Item->ID);
        break;
      case 'ban':
        if ($Item->State == JXW_ITEM_STATE_BINHTHUONG) {
          ajax_SellItem($this->CityID, $Item->ID, $option);
        }
        break;
      case 'thuhoi':
        if ($Item->State == JXW_ITEM_STATE_BINHTHUONG) {
          ajax_DonateItem($this->CityID, $Item->ID);
        }
        break;
      case 'thao':
        if ($Item->State == JXW_ITEM_STATE_BINHTHUONG) {
          ajax_DisassembleItem($this->CityID, $Item->ID, $Item->StaticIndex);
        }
        break;
      case 'mua':
        if ($Item->State == JXW_ITEM_STATE_DANGBAN && $Item->Price<=$option) {
          ajax_BuyItem($this->CityID, $Item->ID, $option);
        }
        break;
      case 'sua':
        if ($Item->State == JXW_ITEM_STATE_TRANGBI) {// chi sua item tren nguoi
          ajax_RepairItemGeneral($this->CityID, $Item->ID);
        }
        break;
      case 'suaki':
        if ($Item->State == JXW_ITEM_STATE_TRANGBI) {// chi sua item tren nguoi
          ajax_RepairItem($this->CityID, $Item->ID);
        }
        break;
      default:
    }
    
    addLog($action . ': '.$Item->Name);
    
    return $ret;
  }
  
  function hiepkhach(&$Hero, $action, $option = 1) {
    addLog('HK '.$Hero['Name'].' bat dau '.$action. ' ('.$option.')');
 
    $this->needUpdate['HeroInfo'] = true;

    switch ($action) {
      case 'chieumo':
        $option = ($option == 'max') ? $Hero['MaxPrenticeNum'] - $Hero['PrenticeNum'] : $option - $Hero['PrenticeNum'];
        $result = ajax_AddHeroEvent($this->CityID, JXW_ACTION_CHIEUMO, 4, $Hero['ID'], $option);
        $H['State'] = JXW_HERO_STATE_CHIEUMO;
        break;
      case 'huanluyen':
        $result = ajax_AddHeroEvent($this->CityID, JXW_ACTION_HUANLUYEN, 4, $Hero['ID'], 0);
        $H['State'] = JXW_HERO_STATE_HUANLUYEN;
        break;
      case 'tancong':
        $result = ajax_ChangeHeroListType($this->CityID, $Hero['ID'], JXW_HERO_LIST_TANCONG);
        $H['ListType'] = JXW_HERO_LIST_TANCONG;
        break;
      case 'haubi':
        $result = ajax_ChangeHeroListType($this->CityID, $Hero['ID'], JXW_HERO_LIST_HAUBI);
        $H['ListType'] = JXW_HERO_LIST_HAUBI;
        break;
      case 'bophong':
        $result = ajax_SetHeroDefence($this->CityID, $Hero['ID'], $option);
        $H['ListType'] = JXW_HERO_LIST_BOPHONG;
        break;
    }
    addLog(Tools::decode($result->data));
  }
}